home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / gnu / gnu_oleo_1_2_2.lha / oleo-1.2.2 / io-curses.c < prev    next >
C/C++ Source or Header  |  1993-03-03  |  29KB  |  1,550 lines

  1. /*    Copyright (C) 1992, 1993 Free Software Foundation, Inc.
  2.  
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2, or (at your option)
  6. any later version.
  7.  
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11. GNU General Public License for more details.
  12.  
  13. You should have received a copy of the GNU General Public License
  14. along with this software; see the file COPYING.  If not, write to
  15. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  16.  
  17.  
  18. #include "proto.h"
  19. #include "funcdef.h"
  20. #include <stdio.h>
  21. #include <curses.h>
  22. #include <fcntl.h>
  23. #include <errno.h>
  24. #include <ctype.h>
  25. #include <signal.h>
  26. #undef NULL
  27. #include "sysdef.h"
  28. #include "global.h"
  29. #include "cell.h"
  30. #include "cmd.h"
  31. #include "line.h"
  32. #include "io-generic.h"
  33. #include "io-edit.h"
  34. #include "io-term.h"
  35. #include "io-abstract.h"
  36. #include "io-utils.h"
  37. #include "lists.h"
  38. #include "window.h"
  39.  
  40. extern unsigned short print_width;
  41.  
  42. /* If 2, clear the top line before reading a character */
  43. /* if 1, clear it after reading a char */
  44. static int topclear = 0;
  45.  
  46. #define MIN_WIN_HEIGHT    (cwin->flags&WIN_EDGES ? 2 : 1)
  47. #define MIN_WIN_WIDTH    (cwin->flags&WIN_EDGES ? 6 : 1)
  48.  
  49. static int redrew = 0;
  50. static int textout = 0;
  51. static int term_cursor_claimed = 0;
  52.  
  53. #ifdef __STDC__
  54. static void move_cursor_to (struct window *, CELLREF, CELLREF, int);
  55. #else
  56. static void move_cursor_to ();
  57. #endif
  58.  
  59.  
  60.  
  61. static void 
  62. _io_display_cell_cursor ()
  63. {
  64.   int cell_cursor_row;
  65.   int cell_cursor_col;
  66.   int cc;
  67.   int rr;
  68.   int cwid;
  69.   int n;
  70.   int x, y;
  71.  
  72.   getyx (stdscr, y, x);
  73.   cell_cursor_col = cwin->win_over;
  74.   for (cc = cwin->screen.lc; cc < cucol; cc++)
  75.     cell_cursor_col += get_width (cc);
  76.   cell_cursor_row = cwin->win_down;
  77.   for (rr = cwin->screen.lr; rr < curow; rr++)
  78.     cell_cursor_row += get_height (rr);
  79.   cwid = get_width (cucol);
  80.   if (cwid > cwin->numc)
  81.     cwid = cwin->numc;
  82.   move (cell_cursor_row, cell_cursor_col);
  83.   standout ();
  84.   for (n = cwid; n; n--)
  85. #ifdef A_STANDOUT
  86.     addch (inch () | A_STANDOUT);
  87. #else
  88.     addch (inch ());
  89. #endif
  90.   standend ();
  91.   move (y, x);
  92. }
  93.  
  94. void 
  95. _io_hide_cell_cursor ()
  96. {
  97.   int cc;
  98.   int rr;
  99.   int cell_cursor_row;
  100.   int cell_cursor_col;
  101.   int cwid;
  102.   int n;
  103.   int x, y;
  104.  
  105.   getyx (stdscr, y, x);
  106.   cell_cursor_col = cwin->win_over;
  107.   for (cc = cwin->screen.lc; cc < cucol; cc++)
  108.     cell_cursor_col += get_width (cc);
  109.   cell_cursor_row = cwin->win_down;
  110.   for (rr = cwin->screen.lr; rr < curow; rr++)
  111.     cell_cursor_row += get_height (rr);
  112.   cwid = get_width (cucol);
  113.   if (cwid > cwin->numc)
  114.     cwid = cwin->numc;
  115.   move (cell_cursor_row, cell_cursor_col);
  116.   for (n = cwid; n; n--)
  117. #ifdef A_STANDOUT
  118.     addch (inch () & ~A_STANDOUT);
  119. #else
  120.     addch (inch ());
  121. #endif
  122.   move (y, x);
  123. }
  124.  
  125.  
  126.  
  127. /* Functions, etc for dealing with cell contents being displayed
  128.     on top of other cells. */
  129.  
  130. struct slops
  131. {
  132.   int s_alloc, s_used;
  133.   struct s
  134.     {
  135.       CELLREF row, clo, chi;
  136.     } s_b[1];
  137. };
  138.  
  139. static void 
  140. flush_slops (where)
  141.      VOIDSTAR where;
  142. {
  143.   struct slops *s;
  144.  
  145.   s = where;
  146.   if (s)
  147.     s->s_used = 0;
  148. }
  149.  
  150. static int 
  151. find_slop (where, r, c, cclp, cchp)
  152.      VOIDSTAR where;
  153.      CELLREF r;
  154.      CELLREF c;
  155.      CELLREF *cclp;
  156.      CELLREF *cchp;
  157. {
  158.   int n;
  159.   struct slops *s;
  160.  
  161.   s = where;
  162.   if (!s)
  163.     return 0;
  164.   for (n = 0; n < s->s_used; n++)
  165.     {
  166.       if (s->s_b[n].row == r && s->s_b[n].clo <= c && s->s_b[n].chi >= c)
  167.     {
  168.       *cclp = s->s_b[n].clo;
  169.       *cchp = s->s_b[n].chi;
  170.       return 1;
  171.     }
  172.     }
  173.   return 0;
  174. }
  175.  
  176. static void 
  177. kill_slop (where, r, clo, chi)
  178.      VOIDSTAR where;
  179.      CELLREF r;
  180.      CELLREF clo;
  181.      CELLREF chi;
  182. {
  183.   int n;
  184.   struct slops *s;
  185.  
  186.   s = where;
  187.   for (n = 0; n < s->s_used; n++)
  188.     {
  189.       if (s->s_b[n].row == r && s->s_b[n].clo == clo && s->s_b[n].chi == chi)
  190.     {
  191.       --(s->s_used);
  192.       s->s_b[n] = s->s_b[s->s_used];
  193.       return;
  194.     }
  195.     }
  196. }
  197.  
  198. static void 
  199. set_slop (wherep, r, clo, chi)
  200.      VOIDSTAR *wherep;
  201.      CELLREF r;
  202.      CELLREF clo;
  203.      CELLREF chi;
  204. {
  205.   int n;
  206.   struct slops **sp;
  207.  
  208.   sp = (struct slops **) wherep;
  209.   if (!*sp)
  210.     {
  211.       (*sp) = ck_malloc (sizeof (struct slops) + 2 * sizeof (struct s));
  212.       (*sp)->s_alloc = 2;
  213.       (*sp)->s_used = 1;
  214.       n = 0;
  215.     }
  216.   else
  217.     {
  218.       n = (*sp)->s_used++;
  219.       if ((*sp)->s_alloc == n)
  220.     {
  221.       (*sp)->s_alloc = n * 2;
  222.       (*sp) = ck_realloc ((*sp), sizeof (struct slops) + n * 2 * sizeof (struct s));
  223.     }
  224.     }
  225.   (*sp)->s_b[n].row = r;
  226.   (*sp)->s_b[n].clo = clo;
  227.   (*sp)->s_b[n].chi = chi;
  228. }
  229.  
  230. static void 
  231. change_slop (where, r, olo, ohi, lo, hi)
  232.      VOIDSTAR where;
  233.      CELLREF r;
  234.      CELLREF olo;
  235.      CELLREF ohi;
  236.      CELLREF lo;
  237.      CELLREF hi;
  238. {
  239.   int n;
  240.   struct slops *s;
  241.  
  242.   s = where;
  243.   for (n = 0; n < s->s_used; n++)
  244.     {
  245.       if (s->s_b[n].row == r && s->s_b[n].clo == olo && s->s_b[n].chi == ohi)
  246.     {
  247.       s->s_b[n].clo = lo;
  248.       s->s_b[n].chi = hi;
  249.       return;
  250.     }
  251.     }
  252. }
  253.  
  254. static void 
  255. _io_open_display ()
  256. {
  257.   initscr ();
  258.   scrollok (stdscr, 0);
  259. #ifdef HAVE_CBREAK
  260.   cbreak ();
  261. #else
  262.   crmode ();
  263. #endif  
  264.   noecho ();
  265.   nonl ();
  266.   /* Must be after initscr() */
  267.   io_init_windows (LINES, COLS - 1, 1, 2, 1, 1, 1, 1);
  268.   print_width = COLS;        /* Make ascii print width == terminal width. */
  269. }
  270.  
  271. static int cursor_cellized = 1;
  272. static void 
  273. _io_cellize_cursor ()
  274. {
  275.   cursor_cellized = 1;
  276. }
  277. static void 
  278. _io_inputize_cursor ()
  279. {
  280.   cursor_cellized = 0;
  281. }
  282.  
  283. static void 
  284. _io_redisp ()
  285. {
  286.   if (!term_cursor_claimed)
  287.     if (cursor_cellized)
  288.       move_cursor_to (cwin, curow, cucol, 0);
  289.     else;
  290.   refresh ();
  291. }
  292.  
  293. static void 
  294. _io_repaint_win (win)
  295.      struct window *win;
  296. {
  297.   io_repaint ();
  298. }
  299.  
  300. static void 
  301. _io_repaint ()
  302. {
  303.   CELLREF cc, rr;
  304.   int n, n1;
  305.   CELL *cp;
  306.   struct window *win;
  307.  
  308.   clear ();
  309.   redrew++;
  310.   for (win = wins; win < &wins[nwin]; win++)
  311.     {
  312.       if (win->lh_wid)
  313.     {
  314.       move (win->win_down - 1, win->win_over - win->lh_wid);
  315.       printw ("#%*d ", win->lh_wid - 2, 1 + win - wins);
  316.       if (win->flags & WIN_EDGE_REV)
  317.         standout ();
  318.       cc = win->screen.lc;
  319.       do
  320.         {
  321.           n = get_width (cc);
  322.           if (n > win->numc)
  323.         n = win->numc;
  324.           if (n > 1)
  325.         {
  326.           char *ptr;
  327.           char buf[30];
  328.  
  329.           if (a0)
  330.             ptr = col_to_str (cc);
  331.           else
  332.             {
  333.               sprintf (buf, "C%u", cc);
  334.               ptr = buf;
  335.             }
  336.           --n;
  337.           n1 = strlen (ptr);
  338.           if (n < n1)
  339.             printw ("%.*s ", n, "###############");
  340.           else
  341.             {
  342.               n1 = (n - n1) / 2;
  343.               printw ("%*s%-*s ", n1, "", n - n1, ptr);
  344.             }
  345.         }
  346.           else if (n == 1)
  347.         addstr ("#");
  348.         }
  349.       while (cc++ < win->screen.hc);
  350.  
  351.       rr = win->screen.lr;
  352.       n = win->win_down;
  353.       do
  354.         {
  355.           n1 = get_height (rr);
  356.           if (n1)
  357.         {
  358.           move (n, win->win_over - win->lh_wid);
  359.           if (a0)
  360.             printw ("%-*d ", win->lh_wid - 1, rr);
  361.           else
  362.             printw ("R%-*d", win->lh_wid - 1, rr);
  363.           n += n1;
  364.         }
  365.         }
  366.       while (rr++ < win->screen.hr);
  367.  
  368.       if (win->flags & WIN_EDGE_REV)
  369.         standend ();
  370.     }
  371.       flush_slops (win->win_slops);
  372.       find_cells_in_range (&(win->screen));
  373.       while (cp = next_row_col_in_range (&rr, &cc))
  374.     if (GET_TYP (cp))
  375.       io_pr_cell_win (win, rr, cc, cp);
  376.     }
  377.   if (!(cp = find_cell (curow, cucol)) || !GET_TYP (cp))
  378.     io_display_cell_cursor ();
  379.   io_update_status ();
  380. }
  381.  
  382. static void 
  383. _io_close_display ()
  384. {
  385.   clear ();
  386.   refresh ();
  387.   (void) endwin ();
  388. }
  389.  
  390. /* This is extern because it was convenient to leave the signal */
  391. /* handler that increments it in io_term.c */
  392. int input_avail_val;
  393.  
  394. static int 
  395. _io_input_avail ()
  396. {
  397.   return (FD_ISSET (0, &read_pending_fd_set)
  398.       || FD_ISSET (0, &exception_pending_fd_set));
  399. }
  400.  
  401. static void 
  402. _io_scan_for_input (block)
  403.      int block;
  404. {
  405.   /* This function only exists because X kbd events don't generate */
  406.   /* SIGIO. Under curses, the SIGIO hander does the work of this */
  407.   /* function. */
  408. }
  409.  
  410. static void 
  411. _io_wait_for_input ()
  412. {
  413.   pause ();
  414. }
  415.  
  416. static int 
  417. _io_read_kbd (buf, size)
  418.      VOLATILE char *buf;
  419.      int size;
  420. {
  421.   int r = read (0, buf, size);
  422.   FD_CLR (0, &read_pending_fd_set);
  423.   FD_CLR (0, &exception_pending_fd_set);
  424.   return r;
  425. }
  426.  
  427.  
  428. #if defined(SIGIO)
  429. static void 
  430. _io_nodelay (delayp)
  431.      int delayp;
  432. {
  433.   panic ("Trying to curses nodelay on a system with SIGIO.");
  434. }
  435.  
  436. #else
  437. static void 
  438. _io_nodelay (delayp)
  439.      int delayp;
  440. {
  441.   nodelay (stdscr, delayp);
  442. }
  443.  
  444. #endif
  445.  
  446. static int 
  447. _io_getch ()
  448. {
  449.   char ch;
  450.   return ((io_read_kbd (&ch, 1) != 1)
  451.       ? EOF
  452.       : ch);
  453. }
  454.  
  455.  
  456. static int 
  457. _io_get_chr (prompt)
  458.      char *prompt;
  459. {
  460.   int x;
  461.   mvaddstr (input, 0, prompt);
  462.   clrtoeol ();
  463.   topclear = 2;
  464.   refresh ();
  465.   ++term_cursor_claimed;
  466.   x = get_chr ();
  467.   --term_cursor_claimed;
  468.   return x;
  469. }
  470.  
  471. #define BUFFER 10
  472.  
  473. #define MORE(bytes)                \
  474.   line_len+=bytes;                \
  475.   line->buf=ck_realloc(sptr,line_len+1);    \
  476.   eptr= eptr-sptr + line->buf;            \
  477.   ptr= ptr-sptr + line->buf;            \
  478.   sptr= line->buf;
  479.  
  480. #define KILLCH()                \
  481. {                        \
  482.  if(ptr!=eptr) {                \
  483.    char *tptr;                    \
  484.    for(tptr=ptr;tptr<=eptr;tptr++) \
  485.      tptr[-1]= tptr[0];    \
  486.  }                    \
  487.  --ptr;                    \
  488.  --eptr;                    \
  489.  --sfilled;                \
  490.  --col;                    \
  491.  if(col<BUFFER)                \
  492.    doscroll++;            \
  493.  else if(!doscroll) {            \
  494.    move(input,col);        \
  495.    delch();            \
  496.    if(eptr-sptr+plen>=COLS && ptr+(COLS-1-col)<eptr) {    \
  497.      mvaddch(input,COLS-1,ptr[COLS-1-col]);\
  498.      domove++;        \
  499.    }                \
  500.  }                    \
  501. }
  502.  
  503. static void 
  504. local_putchar (ch)
  505.      int ch;
  506. {
  507.   (void) putc (ch, stdout);
  508.   /* (void)putchar(ch); */
  509. }
  510.  
  511. static void
  512. local_puts (s)
  513.     char *s;
  514. {
  515.    (void) tputs (s, 1, (int (*)()) local_putchar);
  516. }
  517.  
  518. static void 
  519. beep ()
  520. {
  521. #ifndef HAVE_GETCAP
  522.   putchar ('\007');
  523. #else
  524.   static char *vb;
  525.   static int called = 0;
  526.  
  527.   if (!called)
  528.     {
  529.       called++;
  530.       vb = getcap ("vb");
  531.     }
  532.   if (vb)
  533.     {
  534.       local_puts (vb);
  535.     }
  536.   else
  537.     {
  538.       local_putchar ('\007');
  539.     }
  540. #endif
  541. }
  542.  
  543.  
  544. /* Return zero on success,
  545.    one on empty input,
  546.    and two on abort */
  547. static int 
  548. _io_get_line (prompt, line)
  549.      char *prompt;
  550.      struct line *line;
  551. {
  552.   static int reenter = 0;
  553.   static int over;        /* Overwrite or insert */
  554.   char *ptr;            /* Current position in the line */
  555.   char *sptr;            /* Start of the line */
  556.   char *eptr;            /* End of the line */
  557.   int line_len;            /* length of the line */
  558.   int col = 0;            /* Current cursor column */
  559.   int plen;            /* Length of the prompt */
  560.   int domove = 0;
  561.   int doscroll = 0;
  562.   int c;
  563.   int sfilled;
  564.   char *in_str;
  565.   int n;
  566.   int do_free;
  567.   char vbuf[50];
  568.   int term_cursor_was_claimed = term_cursor_claimed;
  569.  
  570.   if (reenter)
  571.     return 2;
  572.   ++reenter;
  573.  
  574.   topclear = 2;
  575.  
  576.   if (macro_func_arg)
  577.     {
  578.       set_line (line, macro_func_arg);
  579.       macro_func_arg = 0;
  580.       --reenter;
  581.       return 0;
  582.     }
  583.   if (!line->alloc)
  584.     {
  585.       line->alloc = LINE_MIN;
  586.       line->buf = ck_malloc (LINE_MIN);
  587.       line->buf[0] = '\0';
  588.     }
  589.   line_len = line->alloc - 1;    /* Leave room for the NULL */
  590.   sptr = line->buf;
  591.  
  592.   sfilled = strlen (sptr);
  593.   plen = strlen (prompt) + 3;
  594.   ptr = sptr + sfilled;
  595.   eptr = ptr;
  596.   over = 0;
  597.  
  598.   input_active = 1;        /* This effects other-window. */
  599.   term_cursor_claimed = 1;
  600.   doscroll++;
  601.  
  602.   input_active = 1;
  603.   for (;;)
  604.     {
  605.       if (domove)
  606.     {
  607.       domove = 0;
  608.       if (col < BUFFER || col > COLS - BUFFER)
  609.         doscroll++;
  610.       else
  611.         move (input, col);
  612.     }
  613.       if (doscroll)
  614.     {
  615.       doscroll = 0;
  616.       redrew = 0;
  617.       if (textout == 2)
  618.         {
  619.           /* [MORE] the error msg, so the luser has
  620.          a chance to see it. . . */
  621.           mvaddstr (input, COLS - 7, "[MORE]");
  622.           (void) get_chr ();
  623.         }
  624.       textout = 0;
  625.       move (input, 0);
  626.       clrtoeol ();
  627.       if (plen + (ptr - sptr) < COLS - BUFFER)
  628.         {
  629.           *eptr = 0;
  630.           printw ("%s:  %.*s", prompt, COLS - plen, sptr);
  631.           col = plen + (ptr - sptr);
  632.         }
  633.       else
  634.         {
  635.           char *p;
  636.           p = sptr + COLS - 2 * BUFFER - plen;
  637.           while (ptr - p >= COLS - BUFFER)
  638.         p += COLS - 2 * BUFFER;
  639.           *eptr = 0;
  640.           printw ("%.*s", COLS, p);
  641.           col = ptr - p;
  642.         }
  643.       move (input, col);
  644.     }
  645.       if (how_many != 1)
  646.     {
  647.       how_many = 1;
  648.       io_update_status ();
  649.       move (input, col);
  650.     }
  651.       term_cursor_claimed = input_active;
  652.       if (!term_cursor_was_claimed && term_cursor_claimed)
  653.     move (input, col);
  654.       term_cursor_was_claimed = term_cursor_claimed;
  655.       map_chr (input_active ? EDIT_MAP : NAVIGATE_MAP);
  656.     swtch:
  657.       if (cur_vector != EDIT_VECTOR)
  658.     {
  659.       n = global_cmd (EDIT_MAP);
  660.       if (redrew || textout)
  661.         doscroll++;
  662.       if (n == -3)
  663.         {
  664.           *eptr++ = '\0';
  665.           input_active = 0;
  666.           term_cursor_claimed = 0;
  667.           --reenter;
  668.           input_active = 0;
  669.           window_after_input = -1;
  670.           return 2;
  671.         }
  672.       else if (n == -2)
  673.         {
  674.           beep ();
  675.           beep ();
  676.         }
  677.       else if (n >= 0)
  678.         goto swtch;
  679.       continue;
  680.     }
  681.       switch (cur_cmd - edit_funcs)
  682.     {
  683.     case L_BEG_LINE:
  684.       col -= ptr - sptr;
  685.       ptr = sptr;
  686.       domove++;
  687.       break;
  688.  
  689.     case L_BK_CHR:
  690.       for (n = 0; ptr != sptr && n < how_many; n++)
  691.         {
  692.           --ptr;
  693.           --col;
  694.         }
  695.       domove++;
  696.       break;
  697.  
  698.     case L_BK_WORD:
  699.       for (n = 0; ptr != sptr && n < how_many; n++)
  700.         {
  701.           while (ptr != sptr && !isalnum (ptr[-1]))
  702.         {
  703.           --ptr;
  704.           --col;
  705.         }
  706.           while (ptr != sptr && isalnum (ptr[-1]))
  707.         {
  708.           --ptr;
  709.           --col;
  710.         }
  711.         }
  712.       domove++;
  713.       break;
  714.  
  715.     case L_FW_DEL_CHR:
  716.       for (n = 0; ptr != eptr && n < how_many; n++)
  717.         {
  718.           ptr++;
  719.           col++;
  720.           KILLCH ()
  721.         }
  722.       break;
  723.  
  724.     case L_FW_DEL_WORD:
  725.       for (n = 0; ptr != eptr && n < how_many; n++)
  726.         {
  727.           while (ptr != eptr && !isalnum (ptr[0]))
  728.         {
  729.           ptr++;
  730.           col++;
  731.           KILLCH ()
  732.         }
  733.           while (ptr != eptr && isalnum (ptr[0]))
  734.         {
  735.           ptr++;
  736.           col++;
  737.           KILLCH ()
  738.  
  739.         }
  740.         }
  741.       break;
  742.  
  743.     case L_END_LINE:
  744.       col += eptr - ptr;
  745.       ptr = eptr;
  746.       domove++;
  747.       break;
  748.  
  749.     case L_FW_CHR:
  750.       for (n = 0; ptr != eptr && n < how_many; n++)
  751.         {
  752.           col++;
  753.           ptr++;
  754.         }
  755.       domove++;
  756.       break;
  757.  
  758.     case L_FW_WORD:
  759.       for (n = 0; ptr != eptr && n < how_many; n++)
  760.         {
  761.           while (ptr != eptr && !isalnum (ptr[0]))
  762.         {
  763.           col++;
  764.           ptr++;
  765.         }
  766.           while (ptr != eptr && isalnum (ptr[0]))
  767.         {
  768.           col++;
  769.           ptr++;
  770.         }
  771.         }
  772.       domove++;
  773.       break;
  774.  
  775.     case L_FW_DEL_END:
  776.       eptr = ptr;
  777.       clrtoeol ();
  778.       break;
  779.  
  780.     case L_TOGGLE_OVER:
  781.       over = !over;
  782.       break;
  783.  
  784.     case L_BK_DEL_WORD:
  785.       for (n = 0; ptr != sptr && n < how_many; n++)
  786.         {
  787.           while (ptr != sptr && !isalnum (ptr[-1]))
  788.         KILLCH ()
  789.  
  790.           while (ptr != sptr && isalnum (ptr[-1]))
  791.           KILLCH ()
  792.           }
  793.  
  794.           break;
  795.  
  796.     case L_BK_DEL_END:
  797.           while (ptr != sptr)
  798.         KILLCH ()
  799.           break;
  800.  
  801.     case L_BK_DEL_CHR:
  802.           for (n = 0; ptr != sptr && n < how_many; n++)
  803.         KILLCH ()
  804.           break;
  805.  
  806.  
  807.     case L_FINISH:
  808.           *eptr++ = '\0';
  809.           textout = 1;
  810.           input_active = 0;
  811.           term_cursor_claimed = 0;
  812.           --reenter;
  813.           input_active = 0;
  814.           return eptr - sptr == 1 ? 1 : 0;
  815.  
  816.     case L_INS_EXPR:
  817.           {
  818.         CELL *cp;
  819.  
  820.         if (!(cp = find_cell (curow, cucol)))
  821.           break;
  822.         in_str = decomp (curow, cucol, cp);
  823.         do_free = 1;
  824.           }
  825.           goto insert_string;
  826.  
  827.     case L_INS_VAL:
  828.           in_str = cell_value_string (curow, cucol);
  829.           do_free = 0;
  830.           goto insert_string;
  831.  
  832.     case L_INS_REL:
  833.           if (a0)
  834.         {
  835.           if (mkrow != NON_ROW)
  836.             {
  837.               struct rng r;
  838.  
  839.               set_rng (&r, curow, cucol, mkrow, mkcol);
  840.               in_str = range_name (&r);
  841.             }
  842.           else
  843.             in_str = cell_name (curow, cucol);
  844.         }
  845.           else
  846.         {
  847.           if (mkrow != NON_ROW)
  848.             {
  849.               switch (((curow == setrow) << 3)
  850.                   + ((mkrow == setrow) << 2)
  851.                   + ((cucol == setcol) << 1)
  852.                   + (mkcol == setcol))
  853.             {
  854.             case 0:
  855.             case 1:
  856.             case 2:
  857.             case 4:
  858.             case 5:
  859.             case 6:
  860.             case 8:
  861.             case 9:
  862.             case 10:
  863.               sprintf (vbuf, "r[%+d:%+d]c[%+d:%+d]",
  864.                    (curow < mkrow ? curow : mkrow) - setrow,
  865.                    (curow < mkrow ? mkrow : curow) - setrow,
  866.                    (cucol < mkcol ? cucol : mkcol) - setcol,
  867.                    (cucol < mkcol ? mkcol : cucol) - setcol);
  868.               break;
  869.             case 3:
  870.             case 7:
  871.             case 11:
  872.               sprintf (vbuf, "r[%+d:%+d]c",
  873.                    (curow < mkrow ? curow : mkrow) - setrow,
  874.                    (curow < mkrow ? mkrow : curow) - setrow);
  875.               break;
  876.             case 12:
  877.             case 14:
  878.             case 13:
  879.               sprintf (vbuf, "rc[%+d:%+d]",
  880.                    (cucol < mkcol ? cucol : mkcol) - setcol,
  881.                    (cucol < mkcol ? mkcol : cucol) - setcol);
  882.               break;
  883.             case 15:
  884.               strcpy (vbuf, "rc");
  885.               break;
  886. #ifdef TEST
  887.             default:
  888.               panic ("Unknown value");
  889. #endif
  890.             }
  891.             }
  892.           else
  893.             {
  894.               switch (((curow == setrow) << 1) + (cucol == setcol))
  895.             {
  896.             case 0:
  897.               sprintf (vbuf, "r[%+d]c[%+d]", curow - setrow, cucol - setcol);
  898.               break;
  899.             case 1:
  900.               sprintf (vbuf, "r[%+d]c", curow - setrow);
  901.               break;
  902.             case 2:
  903.               sprintf (vbuf, "rc[%+d]", cucol - setcol);
  904.               break;
  905.             case 3:
  906.               strcpy (vbuf, "rc");
  907.               break;
  908. #ifdef TEST
  909.             default:
  910.               panic ("huh what");
  911. #endif
  912.             }
  913.             }
  914.           in_str = vbuf;
  915.         }
  916.           do_free = 0;
  917.           goto insert_string;
  918.  
  919.     case L_INS_ABS:
  920.           /* Insert current cell/range name as an absolute reference */
  921.           if (a0)
  922.         {
  923.           if (mkrow != NON_ROW)
  924.             sprintf (vbuf, "$%s$%u:$%s:$%u", col_to_str (cucol), curow, col_to_str (mkcol), mkrow);
  925.           else
  926.             sprintf (vbuf, "$%s$%u", col_to_str (cucol), curow);
  927.           in_str = vbuf;
  928.         }
  929.           else
  930.         {
  931.           if (mkrow != NON_ROW)
  932.             {
  933.               struct rng r;
  934.  
  935.               set_rng (&r, curow, cucol, mkrow, mkcol);
  936.               in_str = range_name (&r);
  937.             }
  938.           else
  939.             in_str = cell_name (curow, cucol);
  940.         }
  941.           do_free = 0;
  942.  
  943.         insert_string:
  944.           c = strlen (in_str);
  945.           if ((sfilled + (over ? c + (ptr - eptr) : c)) >= line_len)
  946.         {
  947.           n = over ? c + (ptr - eptr) : c;
  948.           if (n < LINE_MIN)
  949.             n = LINE_MIN;
  950.           MORE (n);
  951.         }
  952.           if (over)
  953.         {
  954.           if (ptr + c > eptr)
  955.             {
  956.               sfilled += (ptr + c) - eptr;
  957.               eptr = ptr + c;
  958.             }
  959.         }
  960.           else
  961.         {
  962.           if (ptr != eptr)
  963.             {
  964.               char *tptr;
  965.  
  966.               for (tptr = eptr; tptr >= ptr; --tptr)
  967.             tptr[c] = tptr[0];
  968.             }
  969.           eptr += c;
  970.           sfilled += c;
  971.         }
  972.           bcopy (in_str, ptr, c);
  973.           ptr += c;
  974.           if (col + c >= COLS - BUFFER)
  975.         {
  976.           doscroll++;
  977.         }
  978.           else
  979.         {
  980.           col += c;
  981.           if (!over && ptr != eptr)
  982.             while (c--)
  983.               insch (' ');
  984.           addstr (in_str);
  985.         }
  986.           if (do_free)
  987.         decomp_free ();
  988.           break;
  989.  
  990.     case L_INS_CHR:
  991.           if ((sfilled + how_many + (over ? (ptr - eptr) : (0))) >= line_len)
  992.         {
  993.           n = over ? how_many + (ptr - eptr) : how_many;
  994.           if (n < LINE_MIN)
  995.             n = LINE_MIN;
  996.           MORE (n);
  997.         }
  998.           if (over)
  999.         {
  1000.           if (ptr + how_many > eptr)
  1001.             {
  1002.               sfilled += (ptr + how_many) - eptr;
  1003.               eptr = ptr + how_many;
  1004.             }
  1005.         }
  1006.           else
  1007.         {
  1008.           if (ptr != eptr)
  1009.             {
  1010.               char *tptr;
  1011.  
  1012.               for (tptr = eptr; tptr >= ptr; --tptr)
  1013.             tptr[how_many] = tptr[0];
  1014.             }
  1015.           eptr += how_many;
  1016.           sfilled += how_many;
  1017.         }
  1018.           for (n = 0; n < how_many; n++)
  1019.         *ptr++ = cur_chr;
  1020.  
  1021.           if (col + how_many >= COLS - BUFFER)
  1022.         {
  1023.           doscroll++;
  1024.         }
  1025.           else if (over || ptr == eptr)
  1026.         {
  1027.           col += how_many;
  1028.           for (n = 0; n < how_many; n++)
  1029.             addch (cur_chr);
  1030.         }
  1031.           else
  1032.         {
  1033.           col += how_many;
  1034.           for (n = 0; n < how_many; n++)
  1035.             {
  1036.               insch (cur_chr);
  1037.               move (input, col);
  1038.             }
  1039.         }
  1040.           break;
  1041.         }
  1042.     }
  1043. #undef KILLCH
  1044. #undef BUFFER
  1045. #undef MORE
  1046.     }
  1047.  
  1048. #if __STDC__
  1049.   static void move_cursor_to (struct window *win, CELLREF r, CELLREF c, int dn)
  1050. #else
  1051.   static void
  1052.     move_cursor_to (win, r, c, dn)
  1053.   struct window *win;
  1054.   CELLREF r;
  1055.   CELLREF c;
  1056.   int dn;
  1057. #endif
  1058.   {
  1059.     int cc;
  1060.     int cell_cursor_col;
  1061.     int rr;
  1062.     int cell_cursor_row;
  1063.  
  1064.     cell_cursor_col = win->win_over;
  1065.     for (cc = win->screen.lc; cc < c; cc++)
  1066.       cell_cursor_col += get_width (cc);
  1067.     cell_cursor_row = win->win_down + dn;
  1068.     for (rr = win->screen.lr; rr < r; rr++)
  1069.       cell_cursor_row += get_height (rr);
  1070.     move (cell_cursor_row, cell_cursor_col);
  1071.   }
  1072.  
  1073.   void _io_update_status ()
  1074.   {
  1075.     CELL *cp;
  1076.     char *dec;
  1077.     char *ptr;
  1078.     static char hmbuf[40];
  1079.     int wid;
  1080.     int plen;
  1081.     int dlen;
  1082.     int yy, xx;
  1083.  
  1084.     if (!user_status)
  1085.         return;
  1086.       getyx (stdscr, yy, xx);
  1087.       move (status, 0);
  1088.       wid = COLS - 2;
  1089.  
  1090.     if (mkrow != NON_ROW)
  1091.       {
  1092.     struct rng r;
  1093.  
  1094.       addch ('*');
  1095.     --wid;
  1096.       set_rng (&r, curow, cucol, mkrow, mkcol);
  1097.       ptr = range_name (&r);
  1098.       }
  1099.     else
  1100.         ptr = cell_name (curow, cucol);
  1101.  
  1102.     addstr (ptr);
  1103.     wid -= strlen (ptr);
  1104.  
  1105.     if (how_many != 1)
  1106.       {
  1107.     sprintf (hmbuf, " {%u}", how_many);
  1108.     addstr (hmbuf);
  1109.     wid -= strlen (hmbuf);
  1110.       }
  1111.  
  1112.     if ((cp = find_cell (curow, cucol)) && cp->cell_formula)
  1113.       {
  1114.     dec = decomp (curow, cucol, cp);
  1115.     dlen = strlen (dec);
  1116.       }
  1117.     else
  1118.       {
  1119.     dec = 0;
  1120.     dlen = 0;
  1121.       }
  1122.  
  1123.     ptr = cell_value_string (curow, cucol);
  1124.     plen = strlen (ptr);
  1125.  
  1126.     if (dec)
  1127.       {
  1128.     wid -= 4;
  1129.     if (dlen + plen > wid)
  1130.       {
  1131.         if (plen + 3 > wid)
  1132.           printw (" %.*s... [...]", wid - 6, ptr);
  1133.         else
  1134.           printw (" %s [%.*s...]", ptr, wid - plen - 3, dec);
  1135.       }
  1136.     else
  1137.       printw (" %s [%s]", ptr, dec);
  1138.     decomp_free ();
  1139.       }
  1140.     else if (plen)
  1141.       {
  1142.     --wid;
  1143.     if (plen > wid)
  1144.       printw (" %.*s...", wid - 3, ptr);
  1145.     else
  1146.       printw (" %s", ptr);
  1147.       }
  1148.  
  1149.     clrtoeol ();
  1150.     move (yy, xx);
  1151.   }
  1152.  
  1153. #ifdef __STDC__
  1154. static void 
  1155. _io_info_msg (char * str, ...)
  1156. #else
  1157. static void 
  1158. _io_info_msg (str, va_alist)
  1159.      char *str;
  1160.      va_dcl
  1161. #endif
  1162. {
  1163.     va_list foo;
  1164.     char buf[1000];
  1165.  
  1166.     var_start (foo, str);
  1167.     vsprintf (buf, str, foo);
  1168.     if (!status)
  1169.       {
  1170.     if (textout == 2)
  1171.       {
  1172.         mvaddstr (input, COLS - 7, "[MORE]");
  1173.         ++term_cursor_claimed;
  1174.         (void) get_chr ();
  1175.         --term_cursor_claimed;
  1176.       }
  1177.     textout = 1;
  1178.     mvaddstr (input, 0, buf);
  1179.       }
  1180.     else
  1181.       mvaddstr (status, 0, buf);
  1182.     clrtoeol ();
  1183.     refresh ();
  1184.   }
  1185.  
  1186. #ifdef __STDC__
  1187. static void 
  1188. _io_error_msg (char * str, ...)
  1189. #else
  1190. static void 
  1191. _io_error_msg (str, va_alist)
  1192.      char *str;
  1193.      va_dcl
  1194. #endif
  1195. {
  1196.     va_list foo;
  1197.     char buf[1000];
  1198.     /* (fixme) Sigh.  What I'd give for vprintw() */
  1199.  
  1200. #ifdef TEST
  1201.     extern int isatty ();
  1202.  
  1203.     if (!dbg_do_stderr)
  1204.       dbg_do_stderr = isatty (fileno (stderr)) ? 1 : 2;
  1205. #endif
  1206.     var_start (foo, str);
  1207.     vsprintf (buf, str, foo);
  1208. #ifdef TEST
  1209.     if (dbg_do_stderr == 2)
  1210.       {
  1211.     fputs (buf, stderr);
  1212.     putc ('\n', stderr);
  1213.     fflush (stderr);
  1214.       }
  1215. #endif
  1216.     if (textout == 2)
  1217.       {
  1218.     mvaddstr (input, COLS - 7, "[MORE]");
  1219.     ++term_cursor_claimed;
  1220.     (void) get_chr ();
  1221.     --term_cursor_claimed;
  1222.       }
  1223.     else
  1224.       textout = 2;
  1225.     mvaddstr (input, 0, buf);
  1226.     clrtoeol ();
  1227.     topclear = 1;
  1228.     refresh ();
  1229.   }
  1230.  
  1231.   static int nline;
  1232.   static int save_auto;
  1233.   extern int auto_recalc;
  1234.  
  1235.   static void _io_text_start ()
  1236.   {
  1237.     clear ();
  1238.     io_redisp ();
  1239.     nline = 0;
  1240.     save_auto = auto_recalc;
  1241.     auto_recalc = 0;
  1242.     redrew++;
  1243.     ++term_cursor_claimed;
  1244.   }
  1245.  
  1246. #ifdef __STDC__
  1247. static void 
  1248. _io_text_line (char * ptr, ...)
  1249. #else
  1250. static void 
  1251. _io_text_line (ptr, va_alist)
  1252.      char *ptr;
  1253.      va_dcl
  1254. #endif
  1255. {
  1256.     va_list ap;
  1257.     char sav;
  1258.     char buf[1000];
  1259.  
  1260.     var_start (ap, ptr);
  1261.     vsprintf (buf, ptr, ap);
  1262.     va_end (ap);
  1263.     ptr = buf;
  1264.  
  1265.     for (;;)
  1266.       {
  1267.     if (nline == LINES - 1)
  1268.       {
  1269.         move (nline, 0);
  1270.         addstr ("Press a key to to proceed:  ");
  1271.         refresh ();
  1272.         (void) get_chr ();
  1273.         clear ();
  1274.         nline = 0;
  1275.       }
  1276.     move (nline++, 0);
  1277.     if (strlen (ptr) <= COLS)
  1278.       {
  1279.         addstr (ptr);
  1280.         break;
  1281.       }
  1282.     sav = ptr[COLS];
  1283.     ptr[COLS] = '\0';
  1284.     addstr (ptr);
  1285.     ptr[COLS] = sav;
  1286.     refresh ();
  1287.     ptr += COLS;
  1288.       }
  1289.   }
  1290.  
  1291.   static void _io_text_finish ()
  1292.   {
  1293.     if (nline != 0)
  1294.       {
  1295.     move (nline, 0);
  1296.     addstr ("Press a key to continue:  ");
  1297.     refresh ();
  1298.     (void) get_chr ();
  1299.       }
  1300.     auto_recalc = save_auto;
  1301.     --term_cursor_claimed;
  1302.     io_repaint ();
  1303.   }
  1304.  
  1305.   static void _io_clear_input_before ()
  1306.   {
  1307.     textout = 0;
  1308.     if (topclear == 2)
  1309.       {
  1310.     move (input, 0);
  1311.     clrtoeol ();
  1312.     topclear = 0;
  1313.       }
  1314.     move (0, 0);
  1315.   }
  1316.  
  1317.   static void _io_clear_input_after ()
  1318.   {
  1319.     if (topclear)
  1320.       {
  1321.     move (input, 0);
  1322.     clrtoeol ();
  1323.     topclear = 0;
  1324.       }
  1325.   }
  1326.  
  1327.  
  1328. #if __STDC__
  1329.   static void _io_pr_cell_win (struct window *win, CELLREF r, CELLREF c, CELL *cp)
  1330. #else
  1331.   static void _io_pr_cell_win (win, r, c, cp)
  1332.   struct window *win;
  1333.   CELLREF r;
  1334.   CELLREF c;
  1335.   CELL *cp;
  1336. #endif
  1337.   {
  1338.     int glowing;
  1339.     int lenstr;
  1340.     int j;
  1341.     int wid, wwid;
  1342.     int hgt;
  1343.     char *ptr;
  1344.     int yy, xx;
  1345.  
  1346.     wid = get_width (c);
  1347.     if (!wid)
  1348.       return;
  1349.     if (wid > win->numc)
  1350.       wid = win->numc;
  1351.     hgt = get_height (r);
  1352.     if (!hgt)
  1353.       return;
  1354.     if (hgt > win->numr)
  1355.       hgt = win->numr;
  1356.  
  1357.     getyx (stdscr, yy, xx);
  1358.     glowing = (r == curow && c == cucol && win == cwin);
  1359.     ptr = print_cell (cp);
  1360.     move_cursor_to (win, r, c, 0);
  1361.     if (glowing)
  1362.       standout ();
  1363.     j = GET_JST (cp);
  1364.     if (j == JST_DEF)
  1365.       j = default_jst;
  1366.     lenstr = strlen (ptr);
  1367.  
  1368.     if (lenstr <= wid - 1)
  1369.       {
  1370.     CELLREF ccl, cch;
  1371.  
  1372.     if (j == JST_LFT)
  1373.       printw ("%-*.*s", wid, wid - 1, ptr);
  1374.     else if (j == JST_RGT)
  1375.       printw ("%*.*s ", wid - 1, wid - 1, ptr);
  1376.     else if (j == JST_CNT)
  1377.       {
  1378.         wwid = (wid - 1) - lenstr;
  1379.         printw ("%*s%*s ", (wwid + 1) / 2 + lenstr, ptr, wwid / 2, "");
  1380.       }
  1381. #ifdef TEST
  1382.     else
  1383.       panic ("Unknown justification");
  1384. #endif
  1385.     if (glowing)
  1386.       standend ();
  1387.  
  1388.     if (lenstr == 0 && c > win->screen.lc
  1389.         && find_slop (win->win_slops, r, c - 1, &ccl, &cch))
  1390.       {
  1391.         CELLREF ccdl, ccdh;
  1392.  
  1393.         if (find_slop (win->win_slops, r, c, &ccdl, &ccdh) && ccdl == c)
  1394.           {
  1395.         kill_slop (win->win_slops, r, ccdl, ccdh);
  1396.         for (; ccdh != ccdl; --ccdh)
  1397.           if (ccdh != c && (wwid = get_width (ccdh)))
  1398.             {
  1399.               move_cursor_to (win, r, ccdh, 0);
  1400.               printw ("%*s", wwid, "");
  1401.             }
  1402.           }
  1403.         kill_slop (win->win_slops, r, ccl, cch);
  1404.         io_pr_cell (r, ccl, find_cell (r, ccl));
  1405.       }
  1406.     else if (find_slop (win->win_slops, r, c, &ccl, &cch))
  1407.       {
  1408.         kill_slop (win->win_slops, r, ccl, cch);
  1409.         for (; cch != ccl; --cch)
  1410.           if (cch != c && (wwid = get_width (cch)))
  1411.         {
  1412.           move_cursor_to (win, r, cch, 0);
  1413.           printw ("%*s", wwid, "");
  1414.         }
  1415.         io_pr_cell (r, ccl, find_cell (r, ccl));
  1416.       }
  1417.       }
  1418.     else
  1419.       {
  1420.     CELLREF cc = c;
  1421.     CELL *ccp;
  1422.     CELLREF ccl, cch;
  1423.  
  1424.     for (wwid = wid; lenstr > wwid - 1; wwid += get_width (cc))
  1425.       {
  1426.         if (++cc > win->screen.hc
  1427.         || ((ccp = find_cell (r, cc))
  1428.             && GET_TYP (ccp)
  1429.             && (GET_FMT (ccp) != FMT_HID
  1430.             || (GET_FMT (ccp) == FMT_DEF
  1431.                 && default_fmt != FMT_HID))))
  1432.           {
  1433.         --cc;
  1434.         break;
  1435.           }
  1436.       }
  1437.  
  1438.     if (lenstr > wwid - 1)
  1439.       if (GET_TYP (cp) == TYP_FLT)
  1440.         ptr = adjust_prc (ptr, cp, wwid - 1, wid - 1, j);
  1441.       else if (GET_TYP (cp) == TYP_INT)
  1442.         ptr = (char *) numb_oflo;
  1443.  
  1444.     if (wwid == 1)
  1445.       {
  1446.         addch (' ');
  1447.         if (glowing)
  1448.           standend ();
  1449.       }
  1450.     else if (wwid == wid)
  1451.       {
  1452.         printw ("%-*.*s ", wwid - 1, wwid - 1, ptr);
  1453.         if (glowing)
  1454.           standend ();
  1455.       }
  1456.     else if (glowing)
  1457.       {
  1458.         printw ("%.*s", wid, ptr);
  1459.         standend ();
  1460.         printw ("%-*.*s ", wwid - wid - 1, wwid - wid - 1, ptr + wid);
  1461.       }
  1462.     else if (r == curow && (cucol > c && cucol <= cc))
  1463.       {
  1464.         CELLREF ctmp;
  1465.         int w_left;
  1466.         int w_here;
  1467.  
  1468.         w_left = wid;
  1469.         for (ctmp = c + 1; ctmp < cucol; ctmp++)
  1470.           w_left += get_width (ctmp);
  1471.         printw ("%.*s", w_left, ptr);
  1472.         standout ();
  1473.         w_here = get_width (cucol);
  1474.         if (wwid > w_left + w_here)
  1475.           {
  1476.         printw ("%-*.*s", w_here, w_here, ptr + w_left);
  1477.         standend ();
  1478.         printw ("%-*.*s ",
  1479.          wwid - (w_left + w_here) - 1, wwid - (w_left + w_here) - 1,
  1480.             ptr + w_left + w_here);
  1481.           }
  1482.         else
  1483.           {
  1484.         printw ("%-*.*s", w_here, w_here - 1, ptr + w_left);
  1485.         standend ();
  1486.           }
  1487.       }
  1488.     else
  1489.       printw ("%-*.*s ", wwid - 1, wwid - 1, ptr);
  1490.  
  1491.     if (find_slop (win->win_slops, r, c, &ccl, &cch))
  1492.       {
  1493.         change_slop (win->win_slops, r, ccl, cch, c, cc);
  1494.         for (; cch > cc; --cch)
  1495.           if (wwid = get_width (cch))
  1496.         {
  1497.           move_cursor_to (win, r, cch, 0);
  1498.           printw ("%*s", wwid, "");
  1499.         }
  1500.         for (cch = c - 1; cch > ccl; --cch)
  1501.           if (wwid = get_width (cch))
  1502.         {
  1503.           move_cursor_to (win, r, cch, 0);
  1504.           printw ("%*s", wwid, "");
  1505.         }
  1506.         if (ccl != c)
  1507.           io_pr_cell (r, ccl, find_cell (r, ccl));
  1508.       }
  1509.     else
  1510.       set_slop ((VOIDSTAR *) (&(win->win_slops)), r, c, cc);
  1511.       }
  1512.     if (hgt > 1)
  1513.       {
  1514.     move_cursor_to (win, r, c, 1);
  1515.     ptr = decomp (r, c, cp);
  1516.     printw ("%.*s ", wid - 1, ptr);
  1517.     decomp_free ();
  1518.       }
  1519.     if (glowing)
  1520.       io_update_status ();
  1521.     move (yy, xx);
  1522.   }
  1523.  
  1524.  
  1525.  
  1526. #ifdef __STDC__
  1527. static void
  1528. _io_flush (void)
  1529. #else
  1530. static void
  1531. _io_flush ()
  1532. #endif
  1533. {
  1534.   refresh ();
  1535. }
  1536.  
  1537. #ifdef __STDC__
  1538. void
  1539. tty_graphics (void)
  1540. #else
  1541. void
  1542. tty_graphics ()
  1543. #endif
  1544. {
  1545.  
  1546.   FD_SET (0, &read_fd_set);
  1547.   FD_SET (0, &exception_fd_set);
  1548.   IO_SETUP;
  1549. }
  1550.